package com.locationlib.utils;

import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.telephony.CellInfo;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.CellLocation;
import android.telephony.CellSignalStrengthCdma;
import android.telephony.CellSignalStrengthGsm;
import android.telephony.CellSignalStrengthLte;
import android.telephony.CellSignalStrengthWcdma;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationClientOption.AMapLocationMode;
import com.amap.api.location.AMapLocationClientOption.AMapLocationProtocol;
import com.amap.api.location.AMapLocationListener;
import com.locationlib.listener.OnLocationListener;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

public class LocationUtils {

    private static final String TAG = "LocationUtils";
    private static final int DBM_DEFAULT = -102;
    private AMapLocationClient locationClient;
    private AMapLocationClientOption locationOption;

    private int retryCount = 5;// 失败重试次数
    private int currentCount;
    private boolean isStarting;

    private OnLocationListener listener;

    public void setLocationListener(OnLocationListener listener) {
        this.listener = listener;
    }

    /**
     * 开始定位
     *
     * @author hongming.wang
     * @since 2.8.0
     */
    public void startLocation() {
        if (isStarting) {
            return;
        }
        isStarting = true;
        if (locationClient == null) {
            initLocation(getApplicationByReflect());
        }
        // 设置定位参数
        locationClient.setLocationOption(locationOption);
        // 启动定位
        locationClient.startLocation();
    }

    private static Application getApplicationByReflect() {
        try {
            @SuppressLint("PrivateApi")
            Class<?> activityThread = Class.forName("android.app.ActivityThread");
            Object thread = activityThread.getMethod("currentActivityThread").invoke(null);
            Object app = activityThread.getMethod("getApplication").invoke(thread);
            if (app == null) {
                throw new NullPointerException("u should init first");
            }
            return (Application) app;
        } catch (NoSuchMethodException | IllegalAccessException | ClassNotFoundException |
                 InvocationTargetException e) {
            e.printStackTrace();
        }
        throw new NullPointerException("u should init first");
    }

    /**
     * 停止定位
     *
     * @author hongming.wang
     * @since 2.8.0
     */
    public void stopLocation() {
        // 停止定位
        if (locationClient != null) {
            locationClient.stopLocation();
        }
        currentCount = 0;
        isStarting = false;
    }

    /**
     * 销毁定位
     *
     * @author hongming.wang
     * @since 2.8.0
     */
    public void destroyLocation() {
        if (null != locationClient) {
            /**
             * 如果AMapLocationClient是在当前Activity实例化的， 在Activity的onDestroy中一定要执行AMapLocationClient的onDestroy
             */
            locationClient.onDestroy();
            locationClient = null;
            locationOption = null;
        }
    }

    /**
     * 初始化定位
     *
     * @author hongming.wang
     * @since 2.8.0
     */
    public void initLocation(Context context) {
        // 初始化client
        locationClient = new AMapLocationClient(context);
        locationOption = getDefaultOption();
        // 设置定位参数
        locationClient.setLocationOption(locationOption);
        // 设置定位监听
        locationClient.setLocationListener(locationListener);
    }

    /**
     * 默认的定位参数
     *
     * @author hongming.wang
     * @since 2.8.0
     */
    private AMapLocationClientOption getDefaultOption() {
        AMapLocationClientOption mOption = new AMapLocationClientOption();
        mOption.setLocationMode(AMapLocationMode.Hight_Accuracy);// 可选，设置定位模式，可选的模式有高精度、仅设备、仅网络。默认为高精度模式
        mOption.setGpsFirst(false);// 可选，设置是否gps优先，只在高精度模式下有效。默认关闭
        mOption.setHttpTimeOut(30000);// 可选，设置网络请求超时时间。默认为30秒。在仅设备模式下无效
        mOption.setInterval(2000);// 可选，设置定位间隔。默认为2秒
        mOption.setNeedAddress(true);// 可选，设置是否返回逆地理地址信息。默认是true
        mOption.setOnceLocation(false);// 可选，设置是否单次定位。默认是false
        mOption.setOnceLocationLatest(false);// 可选，设置是否等待wifi刷新，默认为false.如果设置为true,会自动变为单次定位，持续定位时不要使用
        AMapLocationClientOption.setLocationProtocol(AMapLocationProtocol.HTTP);// 可选， 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
        mOption.setSensorEnable(false);// 可选，设置是否使用传感器。默认是false
        mOption.setWifiScan(true); // 可选，设置是否开启wifi扫描。默认为true，如果设置为false会同时停止主动刷新，停止以后完全依赖于系统刷新，定位位置可能存在误差
        mOption.setLocationCacheEnable(false); // 可选，设置是否使用缓存定位，默认为true,这里考虑到缓存可能会获取到错误的定位信息（更换地点后若定位不可用，取得是上一个地点位置信息），因此不使用
        mOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.DEFAULT);// 可选，设置逆地理信息的语言，默认值为默认语言（根据所在地区选择语言）
        return mOption;
    }

    /**
     * 定位监听
     */
    AMapLocationListener locationListener = new AMapLocationListener() {
        @Override
        public void onLocationChanged(AMapLocation location) {
            StringBuffer sb = new StringBuffer();
            if (null != location) {
                Log.e(TAG, location.toString());
                // errCode等于0代表定位成功，其他的为定位失败，具体的可以参照官网定位错误码说明
                if (location.getErrorCode() == 0) {
                    stopLocation();
                    if (listener != null) {
                        listener.onLocationSucc(location);
                    }
                    sb.append("定位成功" + "\n");
                    sb.append("定位类型: " + location.getLocationType() + "\n");
                    sb.append("经    度    : " + location.getLongitude() + "\n");
                    sb.append("纬    度    : " + location.getLatitude() + "\n");
                    sb.append("精    度    : " + location.getAccuracy() + "米" + "\n");
                    sb.append("提供者    : " + location.getProvider() + "\n");

                    sb.append("速    度    : " + location.getSpeed() + "米/秒" + "\n");
                    sb.append("角    度    : " + location.getBearing() + "\n");
                    // 获取当前提供定位服务的卫星个数
                    sb.append("星    数    : " + location.getSatellites() + "\n");
                    sb.append("国    家    : " + location.getCountry() + "\n");
                    sb.append("省            : " + location.getProvince() + "\n");
                    sb.append("市            : " + location.getCity() + "\n");
                    sb.append("城市编码 : " + location.getCityCode() + "\n");
                    sb.append("区            : " + location.getDistrict() + "\n");
                    sb.append("区域 码   : " + location.getAdCode() + "\n");
                    sb.append("地    址    : " + location.getAddress() + "\n");
                    sb.append("兴趣点    : " + location.getPoiName() + "\n");
                    Log.d("location", "result: " + sb.toString());
                    // 定位完成的时间
                } else {
                    // 定位失败
                    // sb.append("定位失败" + "\n");
                    // sb.append("错误码:" + location.getErrorCode() + "\n");
                    // sb.append("错误信息:" + location.getErrorInfo() + "\n");
                    // sb.append("错误描述:" + location.getLocationDetail() + "\n");
                    // 解析定位结果，
                    // String result = sb.toString();
                    if (listener != null) {
                        listener.onLocationError(location);
                    }

                    onRetryFailed();
                }

            } else {
                Log.e(TAG, "定位失败");
                if (listener != null) {
                    listener.onLocationError(location);
                }
                // sb.append("定位失败");
                onRetryFailed();
            }
        }

    };

    private void onRetryFailed() {
        currentCount++;
        // 失败一定次数后不再定位
        if (currentCount > retryCount) {
            stopLocation();
            if (listener != null) {
                listener.onLocationRetryFailed();
            }
        }
    }

    public BaseStationInfo getBaseStationInfo(Context context) {
        try {
            TelephonyManager tel = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            int simState = tel.getSimState();
            if (simState == TelephonyManager.SIM_STATE_ABSENT || simState == TelephonyManager.SIM_STATE_UNKNOWN) {
                // 没有sim卡或者sim不可用
                return null;
            }
            BaseStationInfo baseStationInfo = new BaseStationInfo();
            @SuppressLint("MissingPermission")
            CellLocation cel = tel.getCellLocation();
            int phoneType = tel.getPhoneType();
            // MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();
            // tel.listen(phoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
            baseStationInfo.setPhoneType(phoneType);

            // CDMA 和 GSM 对应不同获取方式
            Log.d("test", "phoneType: " + phoneType);

            if (cel instanceof CdmaCellLocation) {
                baseStationInfo.setPhoneType(TelephonyManager.PHONE_TYPE_CDMA);
                CdmaCellLocation cdmaCellLocation = (CdmaCellLocation) cel;
                String bid = Integer.toHexString(cdmaCellLocation.getBaseStationId());
                String nid = Integer.toHexString(cdmaCellLocation.getNetworkId());
                String sid = Integer.toHexString(cdmaCellLocation.getSystemId());
                baseStationInfo.setBID(bid);
                baseStationInfo.setNID(nid);
                baseStationInfo.setSID(sid);
                Log.d("test", "bid:" + bid + " ,nid: " + nid + " sid: " + sid);
            } else {// 移动联通一致
                GsmCellLocation gsmCellLocation = (GsmCellLocation) cel;
                String cid = Integer.toHexString(gsmCellLocation.getCid());
                String lac = Integer.toHexString(gsmCellLocation.getLac());
                baseStationInfo.setCid(cid);
                baseStationInfo.setLac(lac);
                Log.d("test", "cid:" + cid + " ,lac: " + lac);
            }

            // MCC MNC
            String operator = tel.getNetworkOperator();
            int mcc = Integer.parseInt(operator.substring(0, 3));
            int mnc = Integer.parseInt(operator.substring(3));

            baseStationInfo.setMcc(mcc);
            baseStationInfo.setMnc(mnc);

            // sig
            int sig = getMobileDbm(context);
            String sigStr = "";
            if (sig < 0) {
                String hexString = Integer.toHexString((sig + 65536));
                sigStr = hexString.substring(hexString.length() - 4);
            } else {
                sigStr = Integer.toHexString(sig);
            }
            baseStationInfo.setSig(sigStr);

            Log.d("test", "mcc:" + mcc + " ,mnc: " + mnc + " ,sig: " + sig + " ,sigStr: " + sigStr);

            return baseStationInfo;
        } catch (Exception e) {
            e.printStackTrace();// 没有SIM卡等出错情况
        }

        return null;
    }

    // private class MyPhoneStateListener extends PhoneStateListener {
    // /* 暂时不使用，不好判断sim卡类型 */
    // /* Get the Signal strength from the provider, each tiome there is an update 从得到的信号强度,每个tiome供应商有更新 */
    // @Override
    // public void onSignalStrengthsChanged(SignalStrength signalStrength) {
    // super.onSignalStrengthsChanged(signalStrength);
    // Log.d("test", "onSignalStrengthsChanged>>isGsm:" + signalStrength.isGsm());
    // Log.d("test", "onSignalStrengthsChanged>>getCdmaDbm:" + signalStrength.getCdmaDbm());
    // Log.d("test", "onSignalStrengthsChanged>>getEvdoDbm" + signalStrength.getEvdoDbm());
    // try {
    // int sig = (Integer) signalStrength.getClass().getMethod("getLteSignalStrength").invoke(signalStrength);
    // Log.d("test", "getLteSignalStrength>>" + sig);
    // } catch (Exception e) {
    // e.printStackTrace();
    // }
    // }
    // }

    /**
     * 获取手机信号强度，需添加权限 android.permission.ACCESS_COARSE_LOCATION <br>
     * API要求不低于17 <br>
     *
     * @return 当前手机主卡信号强度, 单位 dBm（-102是默认值，表示获取失败）
     */
    @SuppressLint("NewApi")
    public int getMobileDbm(Context context) {
        int dbm = DBM_DEFAULT;
        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        List<CellInfo> cellInfoList;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            cellInfoList = tm.getAllCellInfo();
            if (null != cellInfoList) {
                for (CellInfo cellInfo : cellInfoList) {
                    if (!cellInfo.isRegistered()) {
                        continue;
                    }
                    if (cellInfo instanceof CellInfoGsm) {
                        CellSignalStrengthGsm cellSignalStrengthGsm = ((CellInfoGsm) cellInfo).getCellSignalStrength();
                        dbm = cellSignalStrengthGsm.getDbm();
                    } else if (cellInfo instanceof CellInfoCdma) {
                        CellSignalStrengthCdma cellSignalStrengthCdma = ((CellInfoCdma) cellInfo)
                                .getCellSignalStrength();
                        dbm = cellSignalStrengthCdma.getDbm();
                    } else if (cellInfo instanceof CellInfoWcdma) {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
                            CellSignalStrengthWcdma cellSignalStrengthWcdma = ((CellInfoWcdma) cellInfo)
                                    .getCellSignalStrength();
                            dbm = cellSignalStrengthWcdma.getDbm();
                        }
                    } else if (cellInfo instanceof CellInfoLte) {
                        CellSignalStrengthLte cellSignalStrengthLte = ((CellInfoLte) cellInfo).getCellSignalStrength();
                        int asuLevel = cellSignalStrengthLte.getAsuLevel();
                        int level = cellSignalStrengthLte.getLevel();
                        dbm = cellSignalStrengthLte.getDbm();
                    }
                }
            }
        }
        dbm = (113 + dbm) / 2;
        Log.d("test", "getMobileDbm>>dbm:" + dbm);
        if (dbm == DBM_DEFAULT) {

        }
        return dbm;
    }

    public int getRetryCount() {
        return retryCount;
    }

    public void setRetryCount(int retryCount) {
        if (isStarting) {
            return;
        }
        this.retryCount = retryCount;
    }
}
